package movieGandalf.GUI;

import java.math.BigInteger;
import java.sql.Connection;

import movieGandalf.BL.ObjectsBL;
import movieGandalf.BL.ObjectsMYSQLBL;
import movieGandalf.GUI.GUIManager.StatusEnum;
import movieGandalf.common.Log;
import movieGandalf.database.MovieTools;
import movieGandalf.logicGuiConnection.*;
import movieGandalf.dataObjects.UserImp;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;



public class LoginPage extends Composite {

	private static final int INDENT_SIZE = 20;
	private static final int IMAGE_SIZE = 180;
	private static final int FIELD_SIZE = 150;
	private static final int BUTTON_SIZE = 70;
	private static final int MARGIN_SIZE = 10;
	private static final int SPACING = 15;

	private User user;
	private Text loginName;
	private Text password;
	private Label lblStatus;
	private Label lblImage;
	private Label lblConfirm;
	private Text confirm;
	private Button loginButton;

	/**
	 * Constructor which builds the login page
	 * 
	 * @param parent
	 * @param style
	 */
	public LoginPage(Composite parent, int style) {
		super(parent, style);

		GUIManager.sendStatus("The Great Gandalf welcomes you!",
				StatusEnum.REGULAR);

		GridLayout gl_loginComposite = new GridLayout(4, false);
		gl_loginComposite.marginTop = MARGIN_SIZE;
		gl_loginComposite.verticalSpacing = SPACING;
		gl_loginComposite.marginLeft = MARGIN_SIZE;
		this.setLayout(gl_loginComposite);

		Label lblWelcome = new Label(this, SWT.BORDER);
		lblWelcome.setFont(SWTResourceManager.getFont("Lucida Grande", 36,
				SWT.BOLD));
		lblWelcome.setText(" WELCOME TO MOVIE GANDALF ");
		lblWelcome.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false,
				false, 4, 1));

		Label lblOptions = new Label(this, SWT.NONE);
		lblOptions.setFont(SWTResourceManager.getFont("Lucida Grande", 12,
				SWT.BOLD));
		GridData gd_lblOptions = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 4, 1);
		gd_lblOptions.verticalIndent = INDENT_SIZE;
		lblOptions.setLayoutData(gd_lblOptions);
		lblOptions.setText("In order to login and see the magic:");

		Label lblActive = new Label(this, SWT.NONE);
		lblActive.setForeground(SWTResourceManager.getColor(204, 0, 204));
		GridData gd_lblActive = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 4, 1);
		gd_lblActive.horizontalIndent = INDENT_SIZE;
		lblActive.setLayoutData(gd_lblActive);
		lblActive.setText("* Existing users: enter your username and password");


		Label lblNonExist = new Label(this, SWT.NONE);
		lblNonExist.setForeground(SWTResourceManager.getColor(0, 102, 255));
		GridData gd_lblNonExist = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 4, 1);
		gd_lblNonExist.horizontalIndent = INDENT_SIZE;
		lblNonExist.setLayoutData(gd_lblNonExist);
		lblNonExist
				.setText("* New users: enter a username and password and a new user will be created");

		Label lblLoginName = new Label(this, SWT.NONE);
		GridData gd_lblLoginName = new GridData(SWT.RIGHT, SWT.CENTER, false,
				false, 1, 1);
		gd_lblLoginName.horizontalIndent = INDENT_SIZE * 3;
		gd_lblLoginName.verticalIndent = INDENT_SIZE * 2;
		lblLoginName.setLayoutData(gd_lblLoginName);
		lblLoginName.setText("User Name:");

		loginName = new Text(this, SWT.BORDER);
		loginName.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent arg0) {
				final String name = loginName.getText();
				loginButton.setEnabled(false);
				Thread newThread = new Thread() {
					public void run() {
						updateCharacter(name);
					}
				};

				newThread.start();
			}
		});
		GridData gd_loginName = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 1, 1);
		gd_loginName.verticalIndent = INDENT_SIZE * 2;
		gd_loginName.widthHint = FIELD_SIZE;
		loginName.setLayoutData(gd_loginName);

		lblStatus = new Label(this, SWT.NONE);
		lblStatus.setAlignment(SWT.CENTER);
		GridData gd_lblStatus = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 1, 1);
		gd_lblStatus.widthHint = BUTTON_SIZE;
		gd_lblStatus.verticalIndent = INDENT_SIZE * 2;
		lblStatus.setLayoutData(gd_lblStatus);

		lblImage = new Label(this, SWT.BORDER);
		GridData gd_lblImage = new GridData(SWT.CENTER, SWT.CENTER, true,
				false, 1, 3);
		gd_lblImage.verticalIndent = INDENT_SIZE;
		gd_lblImage.widthHint = IMAGE_SIZE;
		gd_lblImage.heightHint = IMAGE_SIZE;
		lblImage.setLayoutData(gd_lblImage);

		try {
			lblImage.setImage(new Image(getDisplay(), new Image(this
					.getDisplay(), this.getClass().getResourceAsStream(
					"/images/gandalf.png")).getImageData().scaledTo(IMAGE_SIZE,
					IMAGE_SIZE)));
		} catch (SWTException e) {
			Log.getInstance().WriteMessage(e);
			lblImage.setImage(xImage(IMAGE_SIZE, IMAGE_SIZE));
		}

		Label lblPassword = new Label(this, SWT.NONE);
		lblPassword.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
				false, 1, 1));
		lblPassword.setText("Password:");

		password = new Text(this, SWT.BORDER | SWT.PASSWORD);
		GridData gd_password = new GridData(SWT.LEFT, SWT.CENTER, false, false,
				1, 1);
		gd_password.widthHint = FIELD_SIZE;
		password.setLayoutData(gd_password);

		loginButton = new Button(this, SWT.NONE);
		loginButton.setEnabled(false);
		GridData gd_loginButton = new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 1, 1);
		gd_loginButton.widthHint = BUTTON_SIZE;
		loginButton.setLayoutData(gd_loginButton);
		loginButton.setText("Login");
		this.getShell().setDefaultButton(loginButton);
		loginButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				final String name = loginName.getText();
				final String pass = password.getText();
				
				if (user == null) {
					
					if (!confirm.getText().equalsIgnoreCase(pass)) {
						GUIManager.sendStatus("The two passwords don't match!",
								StatusEnum.ERROR);
						password.setText("");
						confirm.setText("");
						return;
					}
					
					Thread newThread = new Thread() {
						public void run() {
							try {
								Reg(name,pass);
							} catch (Exception e) {
								GUIManager.fatalError(e);
							}
						}
					};
					newThread.start();

				} else {
					
					Thread newThread = new Thread() {
						public void run() {
							try {
								Login(user, pass);
							} catch (Exception e) {
								GUIManager.fatalError(e);
							}
						}
					};
					newThread.start();
				}
			}
		});

		lblConfirm = new Label(this, SWT.NONE);
		lblConfirm.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false,
				1, 1));
		lblConfirm.setText("Confirm:");
		lblConfirm.setVisible(false);

		confirm = new Text(this, SWT.BORDER | SWT.PASSWORD);
		GridData gd_confirm = new GridData(SWT.LEFT, SWT.TOP, false, false, 2,
				1);
		gd_confirm.widthHint = FIELD_SIZE;
		confirm.setLayoutData(gd_confirm);
		confirm.setVisible(false);

	}

	/* This function is used to draw a default error image */
	private Image xImage(int width, int height) {
		Image image = new Image(this.getDisplay(), width, height);
		GC gc = new GC(image);
		gc.setForeground(SWTResourceManager.getColor(SWT.COLOR_RED));
		gc.drawLine(0, 0, width, height);
		gc.drawLine(0, height, width, 0);
		gc.dispose();
		return image;
	}

	/*
	 * This function is used to retrieve the fictional character based on the
	 * name typed in the login name field
	 */
	private void updateCharacter(final String name) {
		
		final User user = (User) MovieTools.getUserByName(MovieTools.getConn(),
				name);

		GUIManager.sendToMainThread(new Runnable() {

			@Override
			public void run() {
				updateScreen(user, name);
			}
		});
	}

	/*
	 * This function updates the screen based on the name typed in the login
	 * name field
	 */
	private void updateScreen(User u, String name) {
		if (this.isDisposed())
			return;

		// In case the field was already changed by the time this function was
		// called
		if (loginName.getText().equalsIgnoreCase(name))
			user = u;
		else
			return;

		if (name.length() == 0) {
			lblStatus.setText("");
			lblConfirm.setVisible(false);
			confirm.setVisible(false);
			confirm.setText("");
			loginButton.setEnabled(false);
			this.setTabList(new Control[] { loginName, password });
		} else if (user == null) {
			lblStatus.setForeground(SWTResourceManager.getColor(0, 102, 255));
			lblStatus.setText("New");
			lblConfirm.setVisible(true);
			confirm.setVisible(true);
			confirm.setText("");
			loginButton.setEnabled(true);
			this.setTabList(new Control[] { loginName, password, confirm,
					loginButton });
		} else if (user != null) {
			lblStatus.setForeground(SWTResourceManager.getColor(50, 205, 50));
			lblStatus.setText("Active");
			lblConfirm.setVisible(false);
			confirm.setVisible(false);
			confirm.setText("");
			loginButton.setEnabled(true);
			this.setTabList(new Control[] { loginName, password, loginButton});
		}

		lblStatus.update();
	}

	/*
	 * This function checks credentials with database in order to log into the
	 * system
	 */
	private void Reg(String name,String pass) throws Exception {
		Connection conn = MovieTools.getConn();
		try {
			User user = new UserImp(null,name,pass,false);
			user.update();
			user = MovieTools.getUserByName(conn, name);
			
			if (user == null) {
				GUIManager.sendStatus("There is currently a connection problem. Please try again later.", StatusEnum.ERROR);
				return;
			}
			
			final User sendUser = user;
			
			Runnable run = new Runnable() {

				@Override
				public void run() {
					GUIManager.login(sendUser);
				}
			};

			GUIManager.sendToMainThread(run);
			
		} catch (Exception e) {
			throw e;
		}
	}
	private void Login(final User user, String pass) throws Exception {

		try {
			if (user == null || !user.isPassword(pass)){
				GUIManager.sendStatus("The password you have entered is incorrect", StatusEnum.ERROR);
				return;
			}
			else{
				Runnable run = new Runnable() {

					@Override
					public void run() {
						GUIManager.login(user);
					}
				};

				GUIManager.sendToMainThread(run);
			}
		} catch (Exception e) {
			throw e;
		}
		
	}

}
